/*
 * SocketException.cpp
 *
 *  Created on: May 10, 2013
 *      Author: Lucifer
 */

#include "../pch.h"
#include "SocketException.h"
#include <errno.h>

#ifndef	_WIN32
#define	NOERROR	0
#endif

namespace BFX
{

/**
 * Initializes a new instance of the SocketException class with the last operating system error code.
 */
SocketException::SocketException()
#ifdef	_WIN32
	: SystemException((int)::WSAGetLastError())
#else
	: SystemException()
#endif
{
	m_socketError = TranslateErrorCode(GetErrorCode());
}

/**
 * Initializes a new instance of the SocketException class with the specified error code.
 * @param nErrorCode
 */
SocketException::SocketException(int nErrorCode)
	: SystemException(nErrorCode)
{
	m_socketError = TranslateErrorCode(nErrorCode);
}

/**
 * Initializes a new instance of the SocketException class with the specified SocketError value.
 * @param socketError
 */
SocketException::SocketException(SocketError socketError)
	: SystemException(TranslateSocketError(socketError))
{
	m_socketError = socketError;
}

SocketException::~SocketException() throw()
{
}

/**
 * Gets the BFX::SocketError value that is associated with this exception.
 * @return The BFX::SocketError value that is associated with this exception.
 */
SocketError SocketException::GetSocketError() const
{
	return m_socketError;
}

/**
 * Gets the error code for this thread's last system sockets operation that failed, and translates to a value
 * defined in BFX::SocketError.
 * @return One of the BFX::SocketError values indicates the error code for this thread's last system sockets
 * operation that failed.
 */
SocketError SocketException::GetLastSocketError()
{
	int nErrorCode =
#ifdef	_WIN32
			WSAGetLastError();
#else
			errno;
#endif
	return TranslateErrorCode(nErrorCode);
}

/**
 * Translates the system error code to a value defined in BFX::SocketError.
 * @param[in] nErrorCode
 * @return One of the BFX::SocketError values.
 */
SocketError SocketException::TranslateErrorCode(int nErrorCode)
{
#ifdef	_WIN32
	switch (nErrorCode)
	{
	case WSAEINTR:
		return SocketError_Interrupted;
	case EACCES:
		return SocketError_AccessDenied;
	case WSAEFAULT:
		return SocketError_Fault;
	case WSAEINVAL:
		return SocketError_InvalidArgument;
	case WSAEMFILE:
		return SocketError_TooManyOpenSockets;
	case WSAEWOULDBLOCK:
		return SocketError_WouldBlock;
	case WSAEINPROGRESS:
		return SocketError_InProgress;
	case WSAEALREADY:
		return SocketError_AlreadyInProgress;
	case WSAENOTSOCK:
		return SocketError_NotSocket;
	case WSAEPROTOTYPE:
		return SocketError_ProtocolType;
	case WSAEPROTONOSUPPORT:
		return SocketError_ProtocolNotSupported;
	case WSAESOCKTNOSUPPORT:
		return SocketError_SocketNotSupported;
	case WSAEPFNOSUPPORT:
		return SocketError_ProtocolFamilyNotSupported;
	case WSAEAFNOSUPPORT:
		return SocketError_AddressFamilyNotSupported;
	case WSAEADDRINUSE:
		return SocketError_AddressAlreadyInUse;
	case WSAEADDRNOTAVAIL:
		return SocketError_AddressNotAvailable;
	case WSAENETDOWN:
		return SocketError_NetworkDown;
	case WSAENETUNREACH:
		return SocketError_NetworkUnreachable;
	case WSAECONNABORTED:
		return SocketError_ConnectionAborted;
	case WSAENOBUFS:
		return SocketError_NoBufferSpaceAvailable;
	case WSAEISCONN:
		return SocketError_IsConnected;
	case WSAENOTCONN:
		return SocketError_NotConnected;
	case WSAESHUTDOWN:
		return SocketError_Shutdown;
	case WSAETIMEDOUT:
		return SocketError_TimedOut;
	case WSAECONNREFUSED:
		return SocketError_ConnectionRefused;
	case WSAEHOSTDOWN:
		return SocketError_HostDown;
	case WSAEHOSTUNREACH:
		return SocketError_HostUnreachable;
	case WSANOTINITIALISED:
		return SocketError_NotInitialized;
	case ERROR_IO_PENDING:
		return SocketError_IOPending;
	case NOERROR:
		return SocketError_Success;
	default:
		BFX_ASSERT1(false, "Should never run on this point.");
		return SocketError_UnspecifiedError;
	}
#else	//	_WIN32
	switch (nErrorCode)
	{
	case EINTR:
		return SocketError_Interrupted;
	case EACCES:
		return SocketError_AccessDenied;
	case EFAULT:
		return SocketError_Fault;
	case EINVAL:
		return SocketError_InvalidArgument;
	case EMFILE:
	case ENFILE:
		return SocketError_TooManyOpenSockets;
	case EWOULDBLOCK:
		return SocketError_WouldBlock;
	case EINPROGRESS:
		return SocketError_InProgress;
	case EALREADY:
		return SocketError_AlreadyInProgress;
	case ENOTSOCK:
		return SocketError_NotSocket;
	case EPROTOTYPE:
		return SocketError_ProtocolType;
	case EPROTONOSUPPORT:
		return SocketError_ProtocolNotSupported;
	case EAFNOSUPPORT:
		return SocketError_AddressFamilyNotSupported;
	case EADDRINUSE:
		return SocketError_AddressAlreadyInUse;
	case EADDRNOTAVAIL:
		return SocketError_AddressNotAvailable;
	case ENETDOWN:
		return SocketError_NetworkDown;
	case ENETUNREACH:
		return SocketError_NetworkUnreachable;
	case ECONNABORTED:
		return SocketError_ConnectionAborted;
	case ENOBUFS:
	case ENOMEM:
		return SocketError_NoBufferSpaceAvailable;
	case EISCONN:
		return SocketError_IsConnected;
	case ENOTCONN:
		return SocketError_NotConnected;
	case ETIMEDOUT:
		return SocketError_TimedOut;
	case ECONNREFUSED:
		return SocketError_ConnectionRefused;
	case EHOSTDOWN:
		return SocketError_HostDown;
	case EHOSTUNREACH:
		return SocketError_HostUnreachable;
	case NOERROR:
		return SocketError_Success;
	default:
		BFX_ASSERT1(false, "Should never run on this point.");
		return SocketError_UnspecifiedError;
	}
#endif	//	!_WIN32
}

/**
 * Translates a value defined in BFX::SocketError to a system error code.
 * @param[in] socketError
 * @return The system error code.
 */
int SocketException::TranslateSocketError(SocketError socketError)
{
#ifdef	_WIN32
	switch (socketError)
	{
	case SocketError_Interrupted:
		return WSAEINTR;
	case SocketError_AccessDenied:
		return EACCES;
	case SocketError_Fault:
		return WSAEFAULT;
	case SocketError_InvalidArgument:
		return WSAEINVAL;
	case SocketError_TooManyOpenSockets:
		return WSAEMFILE;
	case SocketError_WouldBlock:
		return WSAEWOULDBLOCK;
	case SocketError_InProgress:
		return WSAEINPROGRESS;
	case SocketError_AlreadyInProgress:
		return WSAEALREADY;
	case SocketError_NotSocket:
		return WSAENOTSOCK;
	case SocketError_ProtocolType:
		return WSAEPROTOTYPE;
	case SocketError_ProtocolNotSupported:
		return WSAEPROTONOSUPPORT;
	case SocketError_SocketNotSupported:
		return WSAESOCKTNOSUPPORT;
	case SocketError_ProtocolFamilyNotSupported:
		return WSAEPFNOSUPPORT;
	case SocketError_AddressFamilyNotSupported:
		return WSAEAFNOSUPPORT;
	case SocketError_AddressAlreadyInUse:
		return WSAEADDRINUSE;
	case SocketError_AddressNotAvailable:
		return WSAEADDRNOTAVAIL;
	case SocketError_NetworkDown:
		return WSAENETDOWN;
	case SocketError_NetworkUnreachable:
		return WSAENETUNREACH;
	case SocketError_ConnectionAborted:
		return WSAECONNABORTED;
	case SocketError_NoBufferSpaceAvailable:
		return WSAENOBUFS;
	case SocketError_IsConnected:
		return WSAEISCONN;
	case SocketError_NotConnected:
		return WSAENOTCONN;
	case SocketError_Shutdown:
		return WSAESHUTDOWN;
	case SocketError_TimedOut:
		return WSAETIMEDOUT;
	case SocketError_ConnectionRefused:
		return WSAECONNREFUSED;
	case SocketError_HostDown:
		return WSAEHOSTDOWN;
	case SocketError_HostUnreachable:
		return WSAEHOSTUNREACH;
	case SocketError_NotInitialized:
		return WSANOTINITIALISED;
	case SocketError_IOPending:
		return ERROR_IO_PENDING;
	case SocketError_Success:
		return 0;
	default:
		BFX_ASSERT1(false, "Should never run on this point.");
		return SocketError_UnspecifiedError;
	}
#else	//	_WIN32
	switch (socketError)
	{
	case SocketError_Interrupted:
		return EINTR;
	case SocketError_AccessDenied:
		return EACCES;
	case SocketError_Fault:
		return EFAULT;
	case SocketError_InvalidArgument:
		return EINVAL;
	case SocketError_TooManyOpenSockets:
		return ENFILE;
	case SocketError_WouldBlock:
		return EWOULDBLOCK;
	case SocketError_InProgress:
		return EINPROGRESS;
	case SocketError_AlreadyInProgress:
		return EALREADY;
	case SocketError_NotSocket:
		return ENOTSOCK;
	case SocketError_ProtocolType:
		return EPROTOTYPE;
	case SocketError_ProtocolNotSupported:
		return EPROTONOSUPPORT;
	case SocketError_AddressFamilyNotSupported:
		return EAFNOSUPPORT;
	case SocketError_AddressAlreadyInUse:
		return EADDRINUSE;
	case SocketError_AddressNotAvailable:
		return EADDRNOTAVAIL;
	case SocketError_NetworkDown:
		return ENETDOWN;
	case SocketError_NetworkUnreachable:
		return ENETUNREACH;
	case SocketError_ConnectionAborted:
		return ECONNABORTED;
	case SocketError_NoBufferSpaceAvailable:
		return ENOBUFS;
	case SocketError_IsConnected:
		return EISCONN;
	case SocketError_NotConnected:
		return ENOTCONN;
	case SocketError_TimedOut:
		return ETIMEDOUT;
	case SocketError_ConnectionRefused:
		return ECONNREFUSED;
	case SocketError_HostDown:
		return EHOSTDOWN;
	case SocketError_HostUnreachable:
		return EHOSTUNREACH;
	case SocketError_Success:
		return 0;
	default:
		BFX_ASSERT1(false, "Should never run on this point.");
		return SocketError_UnspecifiedError;
	}
#endif	//	_WIN32
}

} /* namespace BFX */
